package com.xyz.apis.common.utils;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
import java.util.Objects;
import java.util.function.Supplier;

public class DateUtil {
    private static final Logger logger = LoggerFactory.getLogger(DateUtil.class);

    public static final String FormatDateTime         = "yyyy-MM-dd HH:mm:ss";
    public static final String FormatDate             = "yyyy-MM-dd";
    public static final String FormatDateTimeNOSecond = "yyyy-MM-dd HH:mm";
    public static final String FormatDateTimeMsec     = "yyyy-MM-dd HH:mm:ss.S";

    public static final String GeneralFormatDateTime  = "y-M-d H:m:s";
    public static final String GeneralFormatDate             = "y-M-d";
    public static final String GeneralSlashFormatDateTime  = "y/M/d H:m:s";
    public static final String GeneralSlashFormatDate  = "y/M/d";

    /**
     * 取当前时间，格式 2015-12-02 16:53:51.0452503
     * <p>
     * >>>>>>>>>>>>>>>>>>>精度有损失，待修改<<<<<<<<<<<<<<<<<<<<
     *
     * @return
     */
    public static String getNow() {
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSSSSS");
        return sf.format(new Date());
    }

    public static Date toDate(String source) {
        SimpleDateFormat sf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
        try {
            return sf.parse(source);
        } catch (ParseException e) {
            logger.error(e.getMessage());
        }
        return null;
    }

    /**
     * 字符串转日期
     *
     * @param source
     * @param format
     * @return
     * @throws ParseException
     */
    public static Date stringToDateFormat(String source, String format){
        SimpleDateFormat sf = new SimpleDateFormat(format);
        try {
            return sf.parse(source);
        } catch (ParseException e) {
            logger.error("格式化异常", e);
        }
        return null;
    }
    /**
     * 日期转字符串
     *
     * @param date
     * @param format
     * @return
     */
    public static String dateToStringFormat(Date date, String format) {
        SimpleDateFormat sf = new SimpleDateFormat(format);
        return sf.format(date);
    }

    public static String dateToCommonString(Date date) {
        if(date==null)
            return "";
       try
       {
           SimpleDateFormat sf = new SimpleDateFormat(FormatDateTime);
           return sf.format(date);
       }
       catch (Exception e)
       {
           return "";
       }
    }

    public static String localDateToStringFormat(LocalDate localDate, String format) {
        if (localDate != null) {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format);
            return formatter.format(localDate);
        }
        return "";
    }

    public static String localDateTimeToStringFormat(LocalDateTime localDateTime, String format) {
        if (localDateTime != null) {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format);
            return formatter.format(localDateTime);
        }
        return "";
    }

    public static LocalDate stringToLocalDateFormat(String dateStr, String format) {
        if (!StringUtils.isEmpty(dateStr) && CommonUtil.isDate(dateStr)) {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format);
            return LocalDate.parse(dateStr, formatter);
        }
        return null;
    }

    /**
     * 转换日期格式(年月日)的字符串为日期格式，否则返回supplier值
     *
     * @param datestr           如果为空，则返回supplier提供的值
     * @param formatter
     * @param localDateSupplier 如果为空抛出空指针异常
     * @return
     */
    public static LocalDate safeConvertLocalDate(String datestr, DateTimeFormatter formatter, Supplier<LocalDate> localDateSupplier) {
        Objects.requireNonNull(localDateSupplier);
        if (StringUtils.isBlank(datestr)) {
            return localDateSupplier.get();
        }
        try {
            return LocalDate.parse(datestr, formatter);
        } catch (Exception e) {
            return localDateSupplier.get();
        }
    }

    /**
     * 对应数据库函数[f_GetRepaymentAdvance_Date]
     * 指定时间=date+months+1day
     *
     * @param date
     * @param months
     * @return
     */
    public static Date nextFewMonth(Date date, Integer months) {
        Objects.requireNonNull(date, "date is null");
        Objects.requireNonNull(months, "months is null");
        return 0 == months ? date : Date.from(LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()).plusMonths(1).plusDays(1).plusMonths((long)(months-1)).atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 对应数据库函数[f_GetMaxRepayment_Date]
     * 指定时间=date+months+1day
     *
     * @param date
     * @param months
     * @param repaymentType
     * @return
     */
    public static Date maxRepaymentDate(Date date,Integer months,Integer repaymentType){
        if(repaymentType==1){
            Objects.requireNonNull(date, "date is null");
            Objects.requireNonNull(months, "months is null");
            return Date.from(LocalDateTime.ofInstant(date.toInstant(),ZoneId.systemDefault()).plusMonths(months).plusDays(1).atZone(ZoneId.systemDefault()).toInstant());
        }else{
            return nextFewMonth(date,months);
        }
    }

    public static String getCurrentTime(){
       return getCurrentTime("yyyy-MM-dd HH:mm:ss");
    }

    public static String getCurrentTime(String format) {
        Date date = new Date();
        SimpleDateFormat dt = new SimpleDateFormat(format);
        return dt.format(date);
    }

    public static String getCurrentDate() {
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd");
        return sf.format(new Date());
    }

    public static String getCurrentMonthFirstDate() {
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-01");
        return sf.format(new Date());
    }

    public static String getCurrentTimeWithOnlyNumber() {
        return getCurrentTime("yyyyMMddHHmmss");
    }

    /**
     * 计算两个日期的时间间隔,返回xx天xx小时xx分钟xx秒
     * @param d1 第一个日期和时间
     * @param d2 第二个日期和时间
     * @return
     */
    public static String diff(LocalDateTime d1,LocalDateTime d2) {
        long begin= Timestamp.valueOf(d1).getTime(),end= Timestamp.valueOf(d2).getTime();
        long between=(end-begin)/1000;//除以1000是为了转换成秒
        long day1=between/(24*3600);
        long hour1=between%(24*3600)/3600;
        long minute1=between%3600/60;
        long second1=between%60;
        return day1+"天"+hour1+"小时"+minute1+"分"+second1+"秒";
    }

    public static Date getNextDay(Date date,int day) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DAY_OF_MONTH, day);//+1今天的时间加一天
        date = calendar.getTime();
        return date;
    }

    public static String getNextDayString(Date date,int day) {
       return dateToCommonString(getNextDay(date,day));
    }

    /**
     * 判断日期是否为今天
     * @param localDateTime 要判断的日期
     * */
    public static boolean isToday(LocalDateTime localDateTime){
        LocalDate date = LocalDate.now();//今天日期
        String d1 = localDateTime.getYear()+""+localDateTime.getMonthValue()+""+localDateTime.getDayOfMonth();
        String d2 = date.getYear()+""+date.getMonthValue()+""+date.getDayOfMonth();
        return d1.equals(d2);
    }

    /**
     * 获取当前日期的前{month}月的年月
     * @param month
     * @return
     */
    public static Date getDateByMonth(Integer month){
        Calendar c = Calendar.getInstance();
        c.setTime(new Date());
        c.add(Calendar.MONTH, -month);
        return c.getTime();
    }


    public static LocalDateTime parse(String time, String... formats) {
        if(StringUtils.isNotBlank(time)){
            String timeStr = time.trim();
            for (String format : formats) {
                try {
                    return LocalDateTime.parse(time, DateTimeFormatter.ofPattern(format));
                } catch (Exception e){
                    logger.warn("日期" + time + "默认格式" + format + "转换异常", e);
                }
            }
            try {
                if(timeStr.contains("-")){
                    if(timeStr.contains(" ")){
                        return LocalDateTime.parse(timeStr, DateTimeFormatter.ofPattern(GeneralFormatDateTime));
                    }else{
                        return LocalDate.parse(timeStr, DateTimeFormatter.ofPattern(GeneralFormatDate)).atStartOfDay();
                    }
                }else if(timeStr.contains("/")){
                    if(timeStr.contains(" ")){
                        return LocalDateTime.parse(timeStr, DateTimeFormatter.ofPattern(GeneralSlashFormatDateTime));
                    }else{
                        return LocalDate.parse(timeStr, DateTimeFormatter.ofPattern(GeneralSlashFormatDate)).atStartOfDay();
                    }
                }
            }catch (Exception e){
                logger.warn("日期" + time + "格式转换异常",e);
            }
        }
        return null;
    }


    /**
     * 计算年龄
     * @param birthDay
     * @return
     * @throws Exception
     */
    public static int getAge(Date birthDay) throws Exception {
        Calendar cal = Calendar.getInstance();
        if (cal.before(birthDay)) {
            //出生日期晚于当前时间，无法计算
            throw new IllegalArgumentException(
                    "The birthDay is before Now.It's unbelievable!");
        }
        int yearNow = cal.get(Calendar.YEAR);  //当前年份
        int monthNow = cal.get(Calendar.MONTH);  //当前月份
        int dayOfMonthNow = cal.get(Calendar.DAY_OF_MONTH); //当前日期
        cal.setTime(birthDay);
        int yearBirth = cal.get(Calendar.YEAR);
        int monthBirth = cal.get(Calendar.MONTH);
        int dayOfMonthBirth = cal.get(Calendar.DAY_OF_MONTH);
        int age = yearNow - yearBirth;   //计算整岁数
        if (monthNow <= monthBirth) {
            if (monthNow == monthBirth) {
                if (dayOfMonthNow < dayOfMonthBirth) age--;//当前日期在生日之前，年龄减一
            }else{
                age--;    //当前月份在生日之前，年龄减一
            }
        }
        return age;
    }

    /**
     *  获取前几个小时的时间
     */
    public static String getBeforeByHourTime(int ihour){
        String returnstr = "";
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.HOUR_OF_DAY, calendar.get(Calendar.HOUR_OF_DAY) - ihour);
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        returnstr = df.format(calendar.getTime());
        return returnstr;
    }

    public static Long getshijianchuo(String str){

        try {
            SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            //设置要读取的时间字符串格式
            Date date = format.parse(str);
            //转换为Date类
            Long timestamp=date.getTime();
            return timestamp;
        } catch (ParseException e) {
            logger.warn("日期" + str + "格式转换异常",e);
        }
        return null;
    }

    /**
     * 返回两个日期之差的值
     * @param start 开始时间
     * @param end   结束时间
     * @param flag  1:天数,2:小时数,3:分钟数、4：毫秒数，5：纳秒数
     * @return
     */
    public static Long diffDetail(LocalDateTime start,LocalDateTime end,Integer flag){
        Duration duration = Duration.between(start,end);
        Long diff =0L;
        switch (flag){
            case 1:
                diff = duration.toDays(); //相差的天数
                break;
            case 2:
                diff = duration.toHours(); //相差的 小时数
                break;
            case 3:
                diff = duration.toMinutes(); //相差的分钟数
                break;
            case 4:
                diff = duration.toMillis(); //相差的毫秒数
                break;
            case 5:
                diff = duration.toNanos(); //相差的纳秒数
                break;
        }
        return diff;
    }

    public static void main(String[] arg){
        System.out.println(getBeforeByHourTime(12));
        LocalDateTime start = LocalDateTime.now().plusMinutes(-3);
        LocalDateTime end = LocalDateTime.now();
        Long aLong = diffDetail(start, end, 3);
        System.out.println("hello"+aLong);

    }
}
